<?php
namespace Hilaoyu\LaravelExtend\Supports;
use Hilaoyu\LaravelExtend\Services\Auth\AuthService;
use Hilaoyu\Utils\UtilStr;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Str;

/**
 * Created by laoyu.
 * User: hilaoyu@qq.com
 * Date: 2018/7/12
 * Time: 下午9:33
 */


class AuthorizeCheck
{
    static $cache_middleware_check=[];
    static $cache_auth_guard_check=[];
    static public function CheckRoute(string $route_name){

        $route_name = trim($route_name);
        $authUserId = AuthService::AuthenticatedUser('id');

        $cache_key = 'laravel_extend_authorize_check_'.UtilStr::replace($route_name,['\\.'=>'_']).'_'.$authUserId.'_'.config('app.env','');
        if(is_bool($has_cache_access = Cache::get($cache_key))){
            return $has_cache_access;
        }

        try{
            $route = \Route::getRoutes()->getByName($route_name);
            if(!$route){
                return false;
            }
            $authorization_middlewares = collect($route->gatherMiddleware())->filter(function ($item){
                return is_string($item) && Str::startsWith($item,'auth:');
            });
            if($authorization_middlewares->isNotEmpty()){
                $has_auth = false;
                $authorization_middlewares->each(function ($authorization_middleware) use (&$has_auth){
                    $middleware_args = explode(',',Str::after($authorization_middleware,'auth:'));
                    if(!empty($middleware_args)){
                        collect($middleware_args)->map(function ($arg){
                            return UtilStr::clearRepeatedChar($arg,['"',"'"],'');
                        })->each(function ($arg) use (&$has_auth){
                            if(array_key_exists($arg,static::$cache_auth_guard_check)){
                                $has_auth = static::$cache_auth_guard_check[$arg];
                            }else{
                                static::$cache_auth_guard_check[$arg] = $has_auth = Auth::guard($arg)->check();
                            }

                            if($has_auth){
                                return false;//跳出循环
                            }
                        });
                    }

                });
                if(!$has_auth){
                    throw new \Exception();
                }
            }




            $access_control_middlewares = collect($route->gatherMiddleware())->filter(function ($item){
                return is_string($item) && Str::startsWith($item,'can:');
            });


            $has_access = true;
            $access_control_middlewares->each(function ($access_control_middleware) use (&$has_access,$route_name){
                if(array_key_exists($access_control_middleware,static::$cache_middleware_check)){
                    $has_auth = static::$cache_middleware_check[$access_control_middleware];
                }else {


                    $middleware_args = explode(',', Str::after($access_control_middleware, 'can:'));
                    $middleware_args = collect($middleware_args)->map(function ($arg) {
                        return UtilStr::clearRepeatedChar($arg, ['"', "'"], '');
                    })->all();

                    $ability = array_shift($middleware_args);
                    //dd($middleware_args);
                    /*if('web.console.access-control.entities' == $route_name){
                        dd($ability,$middleware_args,Gate::check($ability,$middleware_args));
                    }*/
                    static::$cache_middleware_check[$access_control_middleware] = $has_access = Gate::check($ability, $middleware_args);

                    if (!$has_access) {
                        return false;
                    }


                }
            });

            if(!$has_access) {
                throw new \Exception();
            }
            Cache::put($cache_key,true,Carbon::now()->addMinutes(5));
            return true;
        }catch (\Exception $exception){

        }
        Cache::put($cache_key,false,Carbon::now()->addMinutes(5));
        return false;
    }
}
